代码实战会从零开始,开发一个对图片进行马赛克处理的Web应用。它接收用户上传的目标图片,并据此生成相应的马赛克图片。
编程的过程中没有使用第三方库,用的都是Go自带的标准库来完成,可以更好让我们理解Go最基础的一些知识。
这个Web应用的核心是一个Go语言的马赛克算法,下面是这个算法的构思:
(1)通过扫描图片目录,并使用图片的文件名作为键,图片的平均颜色作为值,构建出一个由瓷砖图片组成的散列,也就是一个瓷砖图片数据库。通过计算图片中每个像素红、绿、黄3种颜色的总和,并将它们除以像素的总数量,我们就得到了一个三元组,这个三元组就是图片的平均颜色。
(2)根据瓷砖图片的大小,将目标图片分割成一系列尺寸更小的子图片。
(3)对于目标图片切割出的每张子图片,将它们位于左上方的第一个像素设定为该图片的平均颜色。
(4)根据子图片的平均颜色,在瓷砖图片数据库中找到一张平均颜色与之最接近的瓷砖图片,然后在目标图片的相应位置上使用瓷砖图片去代替原有的子图片。为了找到最接近的平均颜色,程序需要将子图片的平均颜色以及瓷砖图片的平均颜色都转换成三维空间中的一个点,并计算这两个点之间的欧几里得距离。
(5)当一张瓷砖图片被选中之后,程序就会把这张图片从瓷砖图片数据库中移除,以此来保证马赛克图片中的每张瓷砖图片都是独一无二的。
mosaic.go文件实现了上面的马赛克算法,可以在Github上看到:
https://github.com/JimmyLee05/MosaicGo-Web/blob/master/mosaic.go
下面是mosaic.go文件里的各个函数
计算平均颜色的averageColor函数:
averageColor函数把给定图片的每个像素中的红、绿、蓝3种颜色相加起来,并将这些颜色的总和除以图片的像素数量,最后把计算的结果纪录在一个新创建的三元组里面(包含3个元素的数组)。
之后是resize函数,把图片缩放至指定的宽度:
tilesDB函数,通过扫描瓷砖图片所在目录来创建一个瓷砖图片数据库:
瓷砖图片数据库是一个映射,这个映射的键为字符串,而值则为三元组(用包含3个元素的数组来表示)。
通过 getNearestTile函数寻找与目标图片相匹配的瓷砖图片:
getNearestTile函数会把瓷砖图片数据库中的所有纪录与目标图片的平均颜色一一进行对比,而两者欧几里得距离最短的那一条记录,就是与目标图片平均颜色最为接近的瓷砖图片。
马赛克Web应用的main文件
这个文件可以在Github上看到:
https://github.com/JimmyLee05/MosaicGo-Web/blob/master/main.go
main函数:
func main()是 Go语言程序的默认入口函数,函数主体用 {}括号包裹。
main函数只能用于main包中,且只能定义一个。
upload函数:
mosaic函数:
这是并发版的mosaic处理器函数,上传的目标图片被分割成4份来独立处理。在mosaic函数里,程序调用的都是普通函数而不是goroutine,这是因为程序的并发部分存在于被调用函数的内部。cut函数会在内部以goroutine方式执行一个匿名函数,而这个匿名函数则会返回一个通道作为结果。
cut函数:
首先在cut函数里创建一个通道,并启动一个匿名goroutine来计算将要被发送至该通道的马赛克处理结果,接着再把这个通道返回给cut函数的调用者。这样一来,cut函数创建的通道就会立即返回给 mosaic处理器函数,而通道对应的马赛克子图片则会在处理完毕后被发送至通道。
combine函数:
combine函数接受的输入包含了4个来自cut函数的通道,这些通道包含了马赛克图片的各个组成部分,并且程序不知道这些部分什么时候才会通过通道传输过来。为此程序采用select方法,以先到先服务的方式来接收这些通道发送的消息。